home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Libris Britannia 4
/
science library(b).zip
/
science library(b)
/
CUGUK
/
PROG_TOO
/
C027B.ZIP
/
JAS
/
PARSE.C
< prev
next >
Wrap
Text File
|
1990-03-30
|
14KB
|
702 lines
/*
* Copyright (c) 1988 by Sozobon, Limited. Author: Joseph M Treat
*
* Permission is granted to anyone to use this software for any purpose
* on any computer system, and to redistribute it freely, with the
* following restrictions:
* 1) No charge may be made other than reasonable charges for reproduction.
* 2) Modified versions must be clearly marked as such.
* 3) The authors are not responsible for any harmful consequences
* of using this software, even if they result from defects in it.
*/
#include "jas.h"
#include "parse.h"
int line = 1;
int sawerror = 0;
int ignore = 0;
int funny_state = -1;
jmp_buf YYljbuf;
jmp_buf YYopbuf;
YYSTYPE yylval;
int yywidth = 0;
int token = 0;
SYM *cursym = (SYM *) NULL;
extern SYM dot;
extern long newdot;
extern EXPR Yexpr(), Xexpr(), Aexpr(), Sexpr(),
Pexpr(), Mexpr(), Uexpr(), Yfactor();
extern LIST *Yname_list(), *Yexpr_list();
extern OPERAND *Yoperand();
yyparse()
{
token = yylex();
while ( token ) {
Yline();
dot.value = newdot;
}
return sawerror;
}
Yline()
{
if ( setjmp( YYljbuf ) ) {
/*
* Return here on any call to Yerror to gobble up through NL
*/
while ( token && token != NL )
token = yylex();
if ( token ) {
line++;
token = yylex();
}
ignore = 0;
return;
}
if ( Ylabel_list() )
Ystatement();
if ( token != NL )
Yerror( "end of line expected" );
line++;
token = yylex();
ignore = 0;
}
Ylabel_list()
{
while ( token == NAME ) {
cursym = yylval.sym;
token = yylex();
if ( token == _EQU ) {
EXPR val;
if ( cursym->flags & (SEGMT|EQUATED) )
Yerror( "symbol redefinition" );
token = yylex();
val = Yexpr();
if ( val.psym )
Yerror( "illegal equated expression" );
cursym->value = val.value;
cursym->flags |= EQUATED | DEFINED;
return 0;
}
if ( token != COLON )
Yerror( "missing ':'" );
if ( cursym->flags & (SEGMT|EQUATED) )
Yerror( "symbol redefinition" );
cursym->flags |= ( dot.flags & SEGMT ) | DEFINED;
cursym->value = dot.value;
token = yylex();
}
return 1;
}
Ystatement()
{
if ( token != NL ) {
Yinstruction();
cursym = (SYM *) NULL;
}
}
Yinstruction()
{
STMT *sp;
SYM *sym;
EXPR val;
register short size;
register LIST *lp, *xlp;
extern LIST *Yname_list();
extern LIST *Yexpr_list();
switch ( token ) {
default:
Yerror( "syntax error" );
break;
case END:
token = yylex();
break;
case _TEXT:
chsegmt( TXT );
token = yylex();
break;
case _DATA:
chsegmt( DAT );
token = yylex();
break;
case _BSS:
chsegmt( BSS );
token = yylex();
break;
case _GLOBL:
token = yylex();
lp = Yname_list();
for ( ; lp; lp = xlp ) {
xlp = lp->next;
lp->u.sym->flags |= GLOBAL | DEFINED;
free( (char *) lp );
}
break;
case _DC:
size = yywidth;
if ( size == 0 )
Yerror( ".dc must have width specifier" );
token = yylex();
lp = Yexpr_list();
if ( size != 8 ) {
if ( newdot & 1 ) {
zeros( 1L );
if ( cursym != (SYM *) NULL )
cursym->value = newdot;
}
}
for ( ; lp; lp = xlp ) {
xlp = lp->next;
generate(size, GENRELOC, lp->u.val.value, lp->u.sym );
free( (char *) lp );
}
break;
case _ORG:
token = yylex();
val = Yexpr();
if ( val.psym )
Yerror( "illegal use of symbol in expression" );
if ( val.value < newdot )
Yerror( "attempt to move current location backward" );
if ( val.value > newdot ) {
if ( newdot & 1 )
zeros( 1L );
if ( val.value > newdot )
zeros( val.value - newdot );
}
break;
case _DS:
size = yywidth;
if ( size == 0 )
Yerror( ".ds must have width specifier" );
token = yylex();
val = Yexpr();
if ( size != 8 ) {
if ( newdot & 1 ) {
zeros( 1L );
if ( cursym != (SYM *) NULL )
cursym->value = newdot;
}
}
if ( val.psym )
Yerror( "illegal use of symbol in expression" );
zeros( val.value * (size/8) );
break;
case _EVEN:
if ( newdot & 1 ) {
zeros( 1L );
if ( cursym != (SYM *) NULL )
cursym->value = newdot;
}
token = yylex();
break;
case _COMM:
if ( (token = yylex()) != NAME )
Yerror( "missing label" );
sym = yylval.sym;
if ( sym->flags & (SEGMT|EQUATED) )
Yerror( "symbol redefinition" );
if ( (token = yylex()) != COMMA )
Yerror( "missing ','" );
token = yylex();
val = Yexpr();
sym->flags |= EXTERN | DEFINED;
sym->value = val.value;
break;
case INSTR:
sp = yylval.stmt;
sp->op0 = sp->op1 = (OPERAND *) NULL;
token = yylex();
if ( token != NL ) {
sp->op0 = Yoperand();
if ( token == COMMA ) {
token = yylex();
sp->op1 = Yoperand();
}
}
geninst( sp );
break;
}
}
LIST *
Yname_list()
{
register LIST *lp, *xlp;
if ( token != NAME )
Yerror( "label expected" );
lp = xlp = ALLO(LIST);
xlp->next = (LIST *) NULL;
xlp->u.sym = yylval.sym;
token = yylex();
while ( token == COMMA ) {
if ( (token = yylex()) != NAME )
Yerror( "label expected" );
xlp->next = ALLO(LIST);
xlp = xlp->next;
xlp->next = (LIST *) NULL;
xlp->u.sym = yylval.sym;
token = yylex();
}
return lp;
}
LIST *
Yexpr_list()
{
EXPR val;
register LIST *lp;
LIST *xlp, *slp;
extern LIST *make_slist();
if ( token == STRING ) {
lp = make_slist( &xlp, yylval.str );
token = yylex();
free( yylval.str );
} else {
val = Yexpr();
lp = xlp = ALLO(LIST);
xlp->next = (LIST *) NULL;
xlp->u.val = val;
}
while ( token == COMMA ) {
token = yylex();
if ( token == STRING ) {
xlp->next = make_slist( &slp, yylval.str );
xlp = slp;
token = yylex();
free( yylval.str );
} else {
val = Yexpr();
xlp->next = ALLO(LIST);
xlp = xlp->next;
xlp->next = (LIST *) NULL;
xlp->u.val = val;
}
}
return lp;
}
LIST *
make_slist( last, string )
LIST **last;
char *string;
{
char *cp;
LIST *lp, *xlp;
EXPR val;
lp = xlp = (LIST *) NULL;
for ( cp = string; *cp; cp++ ) {
int ch;
if ( *cp == '\\' ) {
switch ( cp[1] ) {
case 'n': ch = '\n'; break;
case 't': ch = '\t'; break;
case 'r': ch = '\r'; break;
case 'b': ch = '\b'; break;
case '0': ch = '\0'; break;
default: ch = cp[1]; break;
}
cp++;
} else {
ch = *cp;
}
if ( lp == (LIST *) NULL ) {
lp = xlp = ALLO(LIST);
xlp->next = (LIST *) NULL;
} else {
xlp->next = ALLO(LIST);
xlp = xlp->next;
xlp->next = (LIST *) NULL;
}
xlp->u.val.psym = (SYM *) NULL;
xlp->u.val.value = ch;
}
*last = xlp;
return lp;
}
OPERAND *
Yoperand()
{
register OPERAND *op;
register int reg, inx;
EXPR val;
op = ALLO(OPERAND);
switch ( token ) {
case SREG:
op->mode = yylval.val;
token = yylex();
break;
case REG:
op->mode = yylval.val < 8 ? O_DN : O_AN;
op->reg = reg = yylval.val;
token = yylex();
if ( token == MINUS || token == DIV ) {
/*
* we have a register mask list
*/
op->mode = O_REGS;
op->expr.value = 1L << reg;
while ( token == MINUS || token == DIV ) {
int tok = token;
token = yylex();
inx = yylval.val;
if ( token != REG )
Yerror("invalid register list");
if ( tok == DIV ) {
op->expr.value |= (1L << inx);
reg = inx;
} else {
int i;
if ( inx < reg )
Yerror("invalid register list");
for ( i = reg+1; i <= inx; i++ )
op->expr.value |= (1L << i);
}
token = yylex();
if ( tok == MINUS && token == MINUS )
Yerror("invalid register list");
}
}
break;
case LP:
if ( (token = yylex()) != REG )
Yerror( "missing register" );
reg = yylval.val;
if ( (token = yylex()) != RP )
Yerror( "missing ')'" );
token = yylex();
if ( token == PLUS ) {
op->mode = O_POST;
op->reg = reg;
token = yylex();
} else {
op->mode = O_INDR;
op->reg = reg;
}
break;
default:
funny_state = 0;
if ( setjmp( YYopbuf ) ) {
/*
* Yexpr() saw MINUS LP REG
*/
reg = yylval.val;
if ( (token = yylex()) != RP )
Yerror( "missing ')'" );
op->mode = O_PRE;
op->reg = reg;
token = yylex();
funny_state = -1;
break;
}
val = Yexpr();
funny_state = -1;
if ( token != LP ) {
op->mode = O_ABS;
op->expr = val;
break;
}
token = yylex();
if ( token == REG ) {
reg = yylval.val;
if ( (token = yylex()) == COMMA ) {
if ( (token = yylex()) != REG )
Yerror( "missing register" );
inx = yylval.val;
if ( yywidth == 8 )
Yerror( "index reg can't be byte" );
if ( yywidth == 32 )
inx |= 0x10;
if ( (token = yylex()) != RP )
Yerror( "missing ')'" );
op->mode = O_INDX;
op->reg = reg;
op->inx = inx;
op->expr = val;
token = yylex();
} else {
if ( token != RP )
Yerror( "missing ')'" );
op->mode = O_DISP;
op->reg = reg;
op->expr = val;
token = yylex();
}
} else if ( token == PC ) {
if ( (token = yylex()) == COMMA ) {
if ( (token = yylex()) != REG )
Yerror( "missing register" );
inx = yylval.val;
if ( yywidth == 8 )
Yerror( "index reg can't be byte" );
if ( yywidth == 32 )
inx |= 0x10;
if ( (token = yylex()) != RP )
Yerror( "missing ')'" );
op->mode = O_PCIX;
op->inx = inx;
op->expr = val;
token = yylex();
} else {
if ( token != RP )
Yerror( "missing ')'" );
op->mode = O_PCRL;
op->expr = val;
token = yylex();
}
} else
Yerror( "register or pc expected" );
break;
case POUND:
token = yylex();
val = Yexpr();
op->mode = O_IMM;
op->expr = val;
break;
}
return op;
}
EXPR
Yexpr()
{
EXPR val1, val2;
val1 = Xexpr();
while ( token == OR ) {
funny_state = -1;
token = yylex();
val2 = Xexpr();
if ( val1.psym || val2.psym )
Yerror( "illegal use of symbol in expression" );
val1.value |= val2.value;
}
return val1;
}
EXPR
Xexpr()
{
EXPR val1, val2;
val1 = Aexpr();
while ( token == XOR ) {
funny_state = -1;
token = yylex();
val2 = Aexpr();
if ( val1.psym || val2.psym )
Yerror( "illegal use of symbol in expression" );
val1.value ^= val2.value;
}
return val1;
}
EXPR
Aexpr()
{
EXPR val1, val2;
val1 = Sexpr();
while ( token == AND ) {
funny_state = -1;
token = yylex();
val2 = Sexpr();
if ( val1.psym || val2.psym )
Yerror( "illegal use of symbol in expression" );
val1.value &= val2.value;
}
return val1;
}
EXPR
Sexpr()
{
register int op;
EXPR val1, val2;
val1 = Pexpr();
while ( token == LSH || token == RSH ) {
op = token;
funny_state = -1;
token = yylex();
val2 = Pexpr();
if ( val1.psym || val2.psym )
Yerror( "illegal use of symbol in expression" );
if ( op == LSH )
val1.value <<= val2.value;
else
val1.value >>= val2.value;
}
return val1;
}
EXPR
Pexpr()
{
register int op;
EXPR val1, val2;
val1 = Mexpr();
while ( token == PLUS || token == MINUS ) {
op = token;
funny_state = -1;
token = yylex();
val2 = Mexpr();
if ( op == PLUS ) {
if ( val1.psym && val2.psym )
Yerror( "illegal use of symbol in expression" );
if ( val2.psym )
val1.psym = val2.psym;
val1.value += val2.value;
} else {
if ( val2.psym )
Yerror( "illegal use of symbol in expression" );
val1.value -= val2.value;
}
}
return val1;
}
EXPR
Mexpr()
{
register int op;
EXPR val1, val2;
jmp_buf oldYYljbuf;
val1 = Uexpr();
while ( token == STAR || token == DIV || token == MOD ) {
op = token;
funny_state = -1;
token = yylex();
val2 = Uexpr();
if ( val1.psym || val2.psym )
Yerror( "illegal use of symbol in expression" );
if ( op == DIV ) {
if ( val2.value == 0L )
Yerror( "divison by zero" );
val1.value /= val2.value;
} else if ( op == MOD ) {
if ( val2.value == 0L )
Yerror( "modulo by zero" );
val1.value %= val2.value;
} else {
val1.value *= val2.value;
}
}
return val1;
}
EXPR
Uexpr()
{
EXPR val;
switch ( token ) {
case MINUS:
if ( funny_state == 0 )
funny_state = 1;
else
funny_state = -1;
token = yylex();
val = Yfactor();
val.value = - val.value;
if ( val.psym )
Yerror( "illegal use of symbol in expression" );
break;
case NOT:
funny_state = -1;
token = yylex();
val = Yfactor();
if ( val.psym )
Yerror( "illegal use of symbol in expression" );
val.value = - val.value;
break;
default:
val = Yfactor();
break;
}
return val;
}
EXPR
Yfactor()
{
EXPR val;
switch ( token ) {
case NUMBER:
funny_state = -1;
val.psym = (SYM *) NULL;
val.value = yylval.val;
break;
case NAME:
funny_state = -1;
if ( yylval.sym->flags & EQUATED ) {
val.psym = (SYM *) NULL;
val.value = yylval.sym->value;
break;
}
val.psym = yylval.sym;
val.value = 0L;
break;
case LP:
if ( funny_state == 1 )
funny_state = 2;
else
funny_state = -1;
token = yylex();
val = Yexpr();
if ( token != RP )
Yerror( "missing ')'" );
break;
case REG:
if ( funny_state == 2 ) {
longjmp( YYopbuf, 1 );
}
default:
Yerror( "illegal expression" );
}
token = yylex();
return val;
}
Yerror( s )
char *s;
{
if (! ignore) {
fprintf( stderr, "jas: line %d ( %s )\n", line, s );
ignore = 1;
}
sawerror = 1;
funny_state = -1;
longjmp( YYljbuf, 1 );
}